﻿%token Identifier ("identifier") : Identifier
%token NullLiteral ("null literal") : NullLiteral
%token BooleanLiteral ("boolean literal") : BooleanLiteral
%token IntegerLiteral ("integer literal") : IntegerLiteral
%token FloatLiteral ("float literal") : FloatLiteral
%token ComplexLiteral ("complex literal") : ComplexLiteral
%token StringLiteral ("string literal") : StringLiteral
%token ByteStringLiteral ("byte string literal") : ByteStringLiteral
%token QuoteStringLiteral ("quote string literal") : StringLiteral
%token QuoteByteStringLiteral ("quote byte string literal") : ByteStringLiteral
%token StackSlotValueReference ("stack slot value reference") : IntegerLiteral
%token StackSlotContextReference ("stack slot context reference") : IntegerLiteral

%token '(', ')'
%token '[', ']'
%token '{', '}'

%xstart DQSTRING, SQSTRING, LDQSTRING, LSQSTRING
%xstart RDQSTRING, RSQSTRING, RLDQSTRING, RLSQSTRING
%xstart IDENTIFIER
%xstart DQBYTES, SQBYTES, LDQBYTES, LSQBYTES
%xstart RDQBYTES, RSQBYTES, RLDQBYTES, RLSQBYTES

Identifier = (name : string)
NullLiteral = (value : object?)
BooleanLiteral = (value : bool)
IntegerLiteral = (value : global::System.Numerics.BigInteger)
FloatLiteral = (value : float64)
ComplexLiteral = (value : global::System.Numerics.Complex)
StringLiteral = (value : string, isQuote : bool?)
ByteStringLiteral = (value : global::System.Collections.ObjectModel.ReadOnlyCollection[byte], isQuote : bool?)
CharLiteral = (value : char32)

%%

%%

lower      = ['a'-'z']
upper      = ['A'-'Z']
digit      = ['0'-'9']
letter     = lower | upper | '_'
identifier = letter (letter | digit)*

line_terminator           = [  '\n' '\v' '\f' '\r' '\x85' '\u2028' '\u2029']
non_line_terminator       = [^ '\n' '\v' '\f' '\r' '\x85' '\u2028' '\u2029']
non_line_terminator_ascii = ['\0'-'\t' '\x0E'-'\x7F']
non_line_terminator_byte  = ['\0'-'\t' '\x0E'-'\xFF']
any_ascii                 = ['\0'-'\x7F']
any_byte                  = ['\0'-'\xFF']
any_char                  = [^]

bin            = ['0' '1']
oct            = ['0'-'7']
hex            = ['0'-'9' 'A'-'F' 'a'-'f']
hex_quad       = hex hex hex hex
non_zero_digit = ['1'-'9']

decimal_integer     = non_zero_digit digit* | '0'+
binary_integer      = '0' ['b' 'B'] bin+
octal_integer       = '0' ['o' 'O'] oct+
hexadecimal_integer = '0' ['x' 'X'] hex+

float_number   = point_float | exponent_float
point_float    = int_part? fraction | int_part '.'
exponent_float = (int_part | point_float) exponent
int_part       = digit+
fraction       = '.' digit+
exponent       = ['e' 'E'] ['+' '-']? digit+

imaginary_number = (float_number | int_part) ['j' 'J']

<*>:
    "(" =>: Level++; yield '('
    ")" =>: Level--; yield ')'
    "[" =>: Level++; yield '['
    "]" =>: Level--; yield ']'
    "{" =>: Level++; yield '{'
    "}" =>: Level--; yield '}'

    'null'  | 'None'    =>: ScanNullValue();            yield NullLiteral
    'true'  | 'True'    =>: ScanBooleanValue(True);     yield BooleanLiteral
    'false' | 'False'   =>: ScanBooleanValue(False);    yield BooleanLiteral
    'inf'               =>: ScanInfinityFloatValue();   yield FloatLiteral
    'nan'               =>: ScanNaNFloatValue();        yield FloatLiteral
    'infj'              =>: ScanInfinityComplexValue(); yield ComplexLiteral
    'nanj'              =>: ScanNaNComplexValue();      yield ComplexLiteral
    identifier          =>: ScanIdentifierName();       yield Identifier
    decimal_integer     =>: ScanIntegerValue(10);       yield IntegerLiteral
    binary_integer      =>: ScanIntegerValue(2);        yield IntegerLiteral
    octal_integer       =>: ScanIntegerValue(8);        yield IntegerLiteral
    hexadecimal_integer =>: ScanIntegerValue(16);       yield IntegerLiteral
    float_number        =>: ScanFloatValue();           yield FloatLiteral
    imaginary_number    =>: ScanComplexValue();         yield ComplexLiteral

    '$' decimal_integer =>: ScanIntegerValue(10, True); yield StackSlotValueReference
    '@' decimal_integer =>: ScanIntegerValue(10, True); yield StackSlotContextReference

    ['u' 'U']? "\""     =>: BeginString(DQSTRING, False)
    ['u' 'U']? "\'"     =>: BeginString(SQSTRING, True)
    ['u' 'U']? "\"\"\"" =>: BeginString(LDQSTRING, False)
    ['u' 'U']? "\'\'\'" =>: BeginString(LSQSTRING, True)

    ['r' 'R']  "\""     =>: BeginString(RDQSTRING, False)
    ['r' 'R']  "\'"     =>: BeginString(RSQSTRING, True)
    ['r' 'R']  "\"\"\"" =>: BeginString(RLDQSTRING, False)
    ['r' 'R']  "\'\'\'" =>: BeginString(RLSQSTRING, True)

    "`"                 =>: BeginString(IDENTIFIER, False)

    ['b' 'B']  "\""     =>: BeginByteString(DQBYTES, False)
    ['b' 'B']  "\'"     =>: BeginByteString(SQBYTES, True)
    ['b' 'B']  "\"\"\"" =>: BeginByteString(LDQBYTES, False)
    ['b' 'B']  "\'\'\'" =>: BeginByteString(LSQBYTES, True)

    (['b' 'B'] ['r' 'R'] | ['r' 'R'] ['b' 'B']) "\""     =>: BeginByteString(RDQBYTES, False)
    (['b' 'B'] ['r' 'R'] | ['r' 'R'] ['b' 'B']) "\'"     =>: BeginByteString(RSQBYTES, True)
    (['b' 'B'] ['r' 'R'] | ['r' 'R'] ['b' 'B']) "\"\"\"" =>: BeginByteString(RLDQBYTES, False)
    (['b' 'B'] ['r' 'R'] | ['r' 'R'] ['b' 'B']) "\'\'\'" =>: BeginByteString(RLSQBYTES, True)

<DQSTRING, SQSTRING, LDQSTRING, LSQSTRING, IDENTIFIER>:
    "\\" line_terminator =>: pass
    "\\\\" =>: AppendChar('\\')
    "\\\"" =>: AppendChar('\"')
    "\\\'" =>: AppendChar('\'')
    "\\a" =>: AppendChar('\a')
    "\\b" =>: AppendChar('\b')
    "\\t" =>: AppendChar('\t')
    "\\n" =>: AppendChar('\n')
    "\\v" =>: AppendChar('\v')
    "\\f" =>: AppendChar('\f')
    "\\r" =>: AppendChar('\r')
    "\\" oct =>: AppendEscape(1, True, True)
    "\\" oct oct =>: AppendEscape(2, True, True)
    "\\" oct oct oct =>: AppendEscape(3, True, True)
    "\\x" hex hex =>: AppendEscape(2, True, False)
    "\\u" hex_quad =>: AppendEscape(4, True, False)
    "\\U" hex_quad hex_quad =>: AppendEscape(8, True, False)

<DQSTRING,  SQSTRING,  LDQSTRING,  LSQSTRING,  \
 RDQSTRING, RSQSTRING, RLDQSTRING, RLSQSTRING, \
 IDENTIFIER>:
    "\\" any_char =>: AppendTokenString()

<DQSTRING, RDQSTRING>:
    "\"" =>: EndString(); yield StringLiteral
<SQSTRING, RSQSTRING>:
    "\'" =>: EndString(); yield QuoteStringLiteral
<IDENTIFIER>:
    "`" =>: EndString(True); yield Identifier
<DQSTRING, RDQSTRING, SQSTRING, RSQSTRING, IDENTIFIER>:
    non_line_terminator =>: AppendTokenString()

<LDQSTRING, RLDQSTRING>:
    "\"\"\"" =>: EndString(); yield StringLiteral
<LSQSTRING, RLSQSTRING>:
    "\'\'\'" =>: EndString(); yield QuoteStringLiteral
<LDQSTRING, RLDQSTRING, LSQSTRING, RLSQSTRING>:
    any_char =>: AppendTokenString()

<DQBYTES, SQBYTES, LDQBYTES, LSQBYTES>:
    "\\" line_terminator =>: pass
    "\\\\" =>: AppendByte('\\')
    "\\\"" =>: AppendByte('\"')
    "\\\'" =>: AppendByte('\'')
    "\\a" =>: AppendByte('\a')
    "\\b" =>: AppendByte('\b')
    "\\t" =>: AppendByte('\t')
    "\\n" =>: AppendByte('\n')
    "\\v" =>: AppendByte('\v')
    "\\f" =>: AppendByte('\f')
    "\\r" =>: AppendByte('\r')
    "\\" oct =>: AppendEscape(1, False, True)
    "\\" oct oct =>: AppendEscape(2, False, True)
    "\\" oct oct oct =>: AppendEscape(3, False, True)
    "\\x" hex hex =>: AppendEscape(2, False, False)

<DQBYTES,  SQBYTES,  LDQBYTES,  LSQBYTES, \
 RDQBYTES, RSQBYTES, RLDQBYTES, RLSQBYTES>:
    "\\" any_ascii =>: AppendTokenStringAsBytes()
    "\\" any_byte =>: raise SyntaxError(SR.NonAsciiByteMustBeXO)
    "\\" any_char =>: raise SyntaxError(SR.EscapedCharNotAscii)

<DQBYTES, RDQBYTES>:
    "\"" =>: EndByteString(); yield ByteStringLiteral
<SQBYTES, RSQBYTES>:
    "\'" =>: EndByteString(); yield QuoteByteStringLiteral
<DQBYTES, RDQBYTES, SQBYTES, RSQBYTES>:
    non_line_terminator_ascii =>: AppendTokenStringAsBytes()
    non_line_terminator_byte =>: raise SyntaxError(SR.NonAsciiByteMustBeXO)
    non_line_terminator =>: raise SyntaxError(SR.CharNotByte)

<LDQBYTES, RLDQBYTES>:
    "\"\"\"" =>: EndByteString(); yield ByteStringLiteral
<LSQBYTES, RLSQBYTES>:
    "\'\'\'" =>: EndByteString(); yield QuoteByteStringLiteral
<LDQBYTES, RLDQBYTES, LSQBYTES, RLSQBYTES>:
    any_ascii =>: AppendTokenStringAsBytes()
    any_byte =>: raise SyntaxError(SR.NonAsciiByteMustBeXO)
    any_char =>: raise SyntaxError(SR.CharNotByte)

<DQSTRING,  SQSTRING,  LDQSTRING,  LSQSTRING,  \
 RDQSTRING, RSQSTRING, RLDQSTRING, RLSQSTRING, \
 DQBYTES,   SQBYTES,   LDQBYTES,   LSQBYTES,   \
 RDQBYTES,  RSQBYTES,  RLDQBYTES,  RLSQBYTES>:
    default =>: raise UnterminatedStringLiteral()

<IDENTIFIER>:
    default =>: raise UnterminatedVerbatimIdentifier()
